<?php

class LeakyDemo{
    private  $lastTime; //起始时间
    public   $burst = 2;// 桶的容量
    public   $rate = 1; // 水漏出的速度,速率
    public   $water;// 当前水量(当前累积请求数)
    public   $redis;

    public function __construct()
    {
        $this->lastTime = time(); //最后一次访问时间
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1',6379);
    }

    public function grant($ip){
        $now = time();

        if(!empty($time = $this->redis->get($ip))){
            $this->lastTime = $time; //获取上一次访问时间
        }

        if(!empty($water = $this->redis->zScore('water', $ip))){
            $this->water = $water; 
        }

        //因为rate是固定的，所以可以认为“时间间隔 * rate”即为漏出的水量
        $s = $now - $this->lastTime; //当前时间减去上次访问时间，得到时间间隔
        $outCount = $s * $this->rate; //漏出的水量（请求数）

        //执行漏水，计算剩余水量+1，也就是当前请求+1
        $this->water = ($this->water - $outCount)+1;

        if($this->water < 0){
            $this->water = 0; //重置为0
        }
        var_dump($this->water.'----桶容量');
        //请求数超出了突发请求限制
        if($this->water > $this->burst){
            return  '超出桶限制';
        }

        $this->lastTime = $now; // 更新时间
        $this->redis->set($ip, $now);
        //记录请求数
        $water++;//更新待请求数
        $this->redis->zAdd('water', $water, $ip);       //存在就修改，不存在就添加
        // $this->redis->zIncrBy('water', 1, $ip);      //存在就+1，不存在就设为1

        return true;
    }
}

$ip = '192.168.30.100';
$demo=new LeakyDemo();

while (true){
    $time = mt_rand(600000,3600000);
    var_dump('执行请求结果:'.$demo->grant($ip));
    var_dump('随机时间:'.$time);
    usleep($time); //随机时间
}

